package com.hq.ims.data.service;

import com.hq.ims.data.config.verification.VdAdd;
import com.hq.ims.data.config.verification.VdEdit;
import com.hq.ims.data.dao.DictMapper;
import com.hq.ims.data.entity.Dict;
import com.hq.ims.data.utils.LocalConstant;
import com.hq.ims.data.vo.DictMapstruct;
import com.hq.mybatis.base.BaseService;
import com.hq.utils.util.*;
import com.hq.utils.vo.SelectVo;
import com.hq.web.utils.SpringBootValidateUtils;
import lombok.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * jiang bai ping
 *
 * @Email 526666031@qq.com
 * @Detail 字典主表服务实现类
 */
@Service
public class BaseDictService extends BaseService<DictMapper, Dict> {

    /**
     * 添加字典
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean addData(
            DictMapstruct.SaveVo saveVo
    ) {
        SpringBootValidateUtils.validate(saveVo, VdAdd.class);
        Dict parentDict = null;
        if (!StringUtils.FH_ZERO.equals(saveVo.getParentId())) {
            parentDict = this.getById(saveVo.getParentId());
        }
        boolean existsName = this.isExistsName(null, saveVo.getParentId(), saveVo.getName());
        BooleanUtils.isTrueThrow(existsName, "名称已经存在");

        //组装数据
        Dict dict = new Dict();

        //排序换位
        int newRankNum = Optional.ofNullable(saveVo.getRankNum()).orElse(this.getMaxRankNum(saveVo.getParentId()) + 1);
        dict.setRankNum(newRankNum);
        Dict rankDict = this.lambdaQuery()
                .eq(Dict::getParentId, saveVo.getParentId())
                .eq(Dict::getRankNum, newRankNum)
                .last(LocalConstant.LIMIT_1)
                .one();
        if (rankDict != null) {
            dict.setRankNum(rankDict.getRankNum());
            this.lambdaUpdate().eq(Dict::getDictId, rankDict.getDictId()).set(Dict::getRankNum, newRankNum).update();
        } else {
            dict.setRankNum(newRankNum);
        }

        dict.setName(StringUtils.ifEmptyDefault(saveVo.getName()));
        dict.setParentId(saveVo.getParentId());
        dict.setRemark(StringUtils.ifEmptyDefault(saveVo.getRemark()));
        dict.setCurNextChildrenCount(0);
        dict.setAllChildrenCount(0);
        dict.setIsCanEditCurNode(true);
        dict.setIsCanEditCurChildrenNodes(true);
        dict.setIsDel(false);
        dict.setParam(StringUtils.ifEmptyDefault(saveVo.getParam()));
        if (parentDict == null) {
            dict.setDictId(SeqUtils.generateUuid());
            dict.setLv(1);
            dict.setRootId(dict.getRootId());
        } else {
            dict.setLv(parentDict.getLv() + 1);
            dict.setRootId(parentDict.getRootId());
        }
        boolean insertBoolean = dict.insert();
        if (!insertBoolean) {
            return false;
        }
        this.updateCount(dict.getRootId());
        return true;
    }

    /**
     * 数据字典
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean updateData(
            @NonNull DictMapstruct.SaveVo saveVo
    ) {
        SpringBootValidateUtils.validate(saveVo, VdEdit.class);
        Dict parentDict = null;
        if (!StringUtils.FH_ZERO.equals(saveVo.getParentId())) {
            parentDict = this.getById(saveVo.getParentId());
        }
        boolean existsName = this.isExistsName(saveVo.getDictId(), saveVo.getParentId(), saveVo.getName());
        BooleanUtils.isTrueThrow(existsName, "名称已经存在");

        //更新数据
        Dict orgDict = this.getById(saveVo.getDictId());
        ObjectUtils.isNullThrow(orgDict, "字典不存在");
        BooleanUtils.isFalseThrow(orgDict.getIsCanEditCurNode(),"当前节点不可编辑");
        //排序换位
        int newRankNum = Optional.ofNullable(saveVo.getRankNum()).orElse(this.getMaxRankNum(saveVo.getParentId()) + 1);
        Dict rankDict = this.lambdaQuery()
                .ne(Dict::getDictId, saveVo.getDictId())
                .eq(Dict::getParentId, saveVo.getParentId())
                .eq(Dict::getRankNum, newRankNum)
                .last(LocalConstant.LIMIT_1)
                .one();
        if (rankDict != null) {
            int ranDictUpdateRankNum = orgDict.getRankNum();
            orgDict.setRankNum(rankDict.getRankNum());
            this.lambdaUpdate().eq(Dict::getDictId, rankDict.getDictId()).set(Dict::getRankNum, ranDictUpdateRankNum).update();
        } else {
            orgDict.setRankNum(newRankNum);
        }

        orgDict.setName(StringUtils.ifEmptyDefault(saveVo.getName()));
        orgDict.setParentId(saveVo.getParentId());
        orgDict.setRemark(StringUtils.ifEmptyDefault(saveVo.getRemark()));
        orgDict.setParam(StringUtils.ifEmptyDefault(saveVo.getParam()));
        if (parentDict != null) {
            //更新子级
            int oldLv = orgDict.getLv();
            int newLv = parentDict.getLv() + 1;
            int diffLv = newLv - oldLv;
            String oldRootId = orgDict.getRootId();

            orgDict.setLv(newLv);
            orgDict.setRootId(parentDict.getRootId());

            if (!parentDict.getDictId().equals(saveVo.getParentId())) {
                this.getBaseMapper().cascadeLv(oldRootId, oldLv, diffLv, parentDict.getRootId());
            }
        }
        boolean updateBoolean = orgDict.updateById();
        if (!updateBoolean) {
            return false;
        }
        this.updateCount(orgDict.getRootId());
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    public int updateCount(String id) {
        Dict dict = this.getById(id);
        if (dict == null) {
            return 0;
        }
        int allChildrenCount = 0;
        List<Dict> childrenList = this.lambdaQuery().select(Dict::getDictId, Dict::getName).eq(Dict::getParentId, dict.getDictId()).list();
        if (ListUtils.isExistsEle(childrenList)) {
            allChildrenCount = childrenList.size() + allChildrenCount;
            List<String> childrenIdList = childrenList.stream().map(Dict::getDictId).collect(Collectors.toList());
            for (String childrenId : childrenIdList) {
                allChildrenCount = allChildrenCount + this.updateCount(childrenId);
            }
        }
        this.lambdaUpdate().eq(Dict::getDictId, id).set(Dict::getCurNextChildrenCount, childrenList.size()).set(Dict::getAllChildrenCount, allChildrenCount).update();
        return allChildrenCount;
    }

    /**
     * 是否存在名称
     *
     * @param dictId   数据ID
     * @param parentId 父ID
     * @param name     名称
     * @return boolean
     */
    public boolean isExistsName(
            String dictId,
            String parentId,
            @NotNull String name
    ) {
        return this.lambdaQuery()
                .ne(StringUtils.isNotEmpty(dictId), Dict::getDictId, dictId)
                .eq(StringUtils.isNotEmpty(parentId), Dict::getParentId, parentId)
                .eq(Dict::getName, name)
                .count() > 0;
    }

    /**
     * 获取最大的排序号
     *
     * @param parentId 父ID
     * @return int
     */
    public Integer getMaxRankNum(String parentId) {
        Dict dict = this.lambdaQuery()
                .eq(Dict::getParentId, parentId)
                .orderByDesc(Dict::getRankNum)
                .last(LocalConstant.LIMIT_1)
                .one();
        if (dict == null) {
            return 0;
        }
        return dict.getRankNum();
    }

    /**
     * 获取树形字典
     *
     * @param parentId 父id
     */
    public List<DictMapstruct.DictTreeVo> getDictTreeByParentId(String parentId) {
        List<Dict> allChildrenList = this.getDictByParentId(parentId);
        List<DictMapstruct.DictTreeVo> dictVoList = DictMapstruct.INSTANCE.toDictTreeVoList(allChildrenList);
        ParentChildrenClassificationUtils.classificationToTree(
                dictVoList,
                d -> d.getDictId(),
                d -> d.getParentId(),
                (d, c) -> d.setChildrenList(c),
                d -> d.setParentId(parentId),
                parentId
        );
        return dictVoList;
    }

    /**
     * 获取树形字典(只有ID,name,childrenList)
     *
     * @param parentId 父id
     */
    public List<SelectVo> getSelectVoTreeByParentId(String parentId) {
        List<Dict> allChildrenList = this.getDictByParentId(parentId);
        List<SelectVo> selectVoList = SelectVoUtils.convertBeanToSelect(allChildrenList, d -> d.getDictId(), d -> d.getName());
        ParentChildrenClassificationUtils.classificationToTree(
                selectVoList,
                d -> d.getId(),
                d -> d.getParentId(),
                (d, c) -> d.setChildrenList(c),
                d -> d.setParentId(parentId),
                parentId
        );
        return selectVoList;
    }


    public List<Dict> getDictByParentId(String parentId) {
        List<Dict> list = this.lambdaQuery().eq(Dict::getParentId, parentId).orderByAsc(Dict::getRankNum).list();
        return list;
    }
}
